<script>
/**
 * @Author: 焦质晔
 * @Date: 2019-06-20 10:00:00
 * @Last Modified by: 焦质晔
 * @Last Modified time: 2020-02-27 15:09:27
 **/
import _ from 'lodash';
import { search, save } from '@/api/components';
import { authority } from '../../utils/authMixin';
export default {
  name: 'ColumnFilter',
  mixins: [authority],
  props: {
    columns: {
      type: Array,
      required: true,
      default: () => []
    },
    columnsRef: {
      type: String,
      default: ''
    },
    onColumnsChange: {
      type: Function,
      required: true
    },
    isServerColumnsRef: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      // 列筛选选中的 key
      checkedKeys: this.createCheckedKeys(this.columns),
      // 列筛选数据列表
      treeList: this.createTreeList(this.columns),
      // 全选/反选
      checkedAll: !0,
      // 保存筛选记录
      isSave: false
    };
  },
  watch: {
    columns(nextProps, prevProps) {
      if (_.isEqual(nextProps, prevProps)) return;
      this.checkedKeys = this.createCheckedKeys(nextProps);
      this.treeList = this.createTreeList(nextProps);
      this.setLocalColumns(nextProps);
    }
  },
  created() {
    this.initial();
  },
  methods: {
    // 创建树结构列表数据
    createTreeList(columns) {
      return columns.map(column => ({ dataIndex: column.dataIndex, label: column.title }));
    },
    // 创建树结构选中数组
    createCheckedKeys(columns) {
      return columns.filter(column => !column.hidden).map(x => x.dataIndex);
    },
    // 列排序拖拽相关方法
    allowDropHandler(draggingNode, dropNode, type) {
      return type !== 'inner';
    },
    // 列排序拖拽相关方法
    nodeDropHandler(draggingNode, dropNode, dropType, ev) {
      this.$refs.tree.setChecked(draggingNode.key, draggingNode.checked);
      const newColumns = this.treeList.map(item => this.columns.find(column => column.dataIndex === item.dataIndex));
      this.onColumnsChange(this.createChangedColumns(newColumns));
    },
    // 当树节点选中状态变化时
    handleCheckChange(data, checked, indeterminate) {
      this.onColumnsChange(this.createChangedColumns(this.columns));
    },
    // 列筛选的选中状态切换
    createChangedColumns(columns) {
      this.checkedKeys = this.$refs.tree.getCheckedKeys();
      this.checkedAll = this.checkedKeys.length === this.columns.length;
      return columns.map(column => {
        const target = { ...column };
        target.hidden = !this.checkedKeys.includes(target.dataIndex);
        return target;
      });
    },
    // 做 columns 本地存储
    setLocalColumns(columns) {
      if (!this.columnsRef) return;
      const result = columns.map(column => {
        const target = {};
        if (typeof column.width !== 'undefined') {
          target.width = column.width;
        }
        if (typeof column.minWidth !== 'undefined') {
          target.minWidth = column.minWidth;
        }
        return {
          dataIndex: column.dataIndex,
          hidden: Boolean(column.hidden),
          ...target
        };
      });
      // 本地存储
      localStorage.setItem(this.columnsRef, JSON.stringify(result));
    },
    // 获取本地存储 columns 信息
    getColumnsConfig() {
      if (!this.columnsRef) return;
      // 本地存储
      const res = localStorage.getItem(this.columnsRef);
      if (res === null) return;
      const columns = res ? JSON.parse(res) : [];
      if (!Array.isArray(columns)) return;
      // 清空本地存储
      if (columns.length !== this.columns.length) {
        localStorage.removeItem(this.columnsRef);
        return;
      }
      // return columns.map(x => ({ ...this.columns.find(column => column.dataIndex === x.dataIndex), ...x }));
      return columns.map(x => {
        let localColumn = this.columns.find(column => column.dataIndex === x.dataIndex);
        return {
          ...localColumn,
          ...{ hidden: x.hidden, width: x.width || (localColumn ? localColumn.width : '') || '' }
        };
      });
    },
    getFetchSearch(fn) {
      search({ menuId: this.getmenuId, columnsRef: this.columnsRef, table: this.columns }).then(res => {
        if (res && res.success && res.data.menuId == this.getmenuId && res.data[this.columnsRef].length) {
          const data = JSON.stringify(res.data[this.columnsRef]);
          const columns = res.data[this.columnsRef];
          if (data === localStorage.getItem(this.columnsRef)) return !1;
          // 更新本地存储
          // 合并本地和云端的数组，新增的放到最后
          if (columns.length < this.columns.length) {
            // 云端的少，新加字段了
            let addItems = this.columns.filter(item => !columns.find(x => x.dataIndex == item.dataIndex));
            addItems.forEach(x => {
              columns.push(x);
            });
          } else if (columns.length > this.columns.length) {
            // 本地的少，删除字段了
            let deleteItems = columns.filter(item => !this.columns.find(x => x.dataIndex == item.dataIndex));
            deleteItems.forEach(item => {
              let index = columns.findIndex(x => x.dataIndex == item.dataIndex);
              if (index != -1) {
                // 找到就删除
                columns.splice(index, 1);
              }
            });
          }
          localStorage.setItem(this.columnsRef, JSON.stringify(columns));
          fn && fn(this.getColumnsConfig());
        }
      });
    },
    onSaveHandle(val) {
      this.isSave = val;
      // 保存接口逻辑
      save({ menuId: this.getmenuId, columnsRef: this.columnsRef, table: this.columns });
    },
    // 初始化
    initial() {
      const localColumns = this.getColumnsConfig();
      // 优先读取本地缓存
      !!localColumns && this.setColumnsStatus(localColumns);
      // 更新服务器缓存数据到本地
      this.isServerColumnsRef &&
        this.getFetchSearch(resColumns => {
          this.setColumnsStatus(resColumns);
        });
    },
    // 设置缓存数据到组件
    setColumnsStatus(columns) {
      this.checkedKeys = this.createCheckedKeys(columns);
      this.treeList = this.createTreeList(columns);
      this.onColumnsChange(columns);
    },
    // 公开到外部的方法
    SET_COLUMN_INFO(obj) {
      const result = this.columns.map(column => {
        const [key] = Object.keys(obj);
        if (column.dataIndex === key) {
          column.width = obj[key];
        }
        return column;
      });
      this.setLocalColumns(result);
    },
    handleCheckAllChange(value) {
      const columns = [].concat(this.columns);
      this.checkedAll = value;
      columns.forEach(x => this.$refs.tree.setChecked(x.dataIndex, value));
    },
    visibleChangeHandle(val) {
      this.isSave = !val;
    }
  },
  render() {
    const { treeList, checkedKeys, checkedAll, isServerColumnsRef, isSave } = this;
    return (
      <el-dropdown hide-on-click={false} trigger="click" {...{ on: { 'visible-change': this.visibleChangeHandle } }}>
        <span class="columns-dropdown">
          <i class="icon el-icon-s-operation" />
          列筛选排序
        </span>
        <el-dropdown-menu style={{ minWidth: '120px', maxHeight: 'calc(100vh - 30px)', overflowY: 'auto' }} slot="dropdown">
          <el-checkbox class="columns-tree cAll" value={checkedAll} onChange={this.handleCheckAllChange}>
            全/反选
          </el-checkbox>
          {isServerColumnsRef && (
            <div style={{ textAlign: 'center' }}>
              <el-switch
                style={{ display: 'block', padding: '5px 0 8px 0', borderBottom: '1px solid #ccc' }}
                disabled={isSave}
                value={isSave}
                activeText="保存"
                {...{ on: { change: this.onSaveHandle } }}
              />
            </div>
          )}
          <el-tree
            ref="tree"
            class="columns-tree"
            node-key="dataIndex"
            data={treeList}
            check-on-click-node={true}
            show-checkbox
            draggable
            default-checked-keys={checkedKeys}
            allow-drop={this.allowDropHandler}
            on-node-drop={this.nodeDropHandler}
            on-check-change={this.handleCheckChange}
          />
        </el-dropdown-menu>
      </el-dropdown>
    );
  }
};
</script>

<style lang="less">
.columns-dropdown {
  cursor: pointer;
  color: @primaryColor;
  .icon {
    margin-right: 4px;
    font-weight: 700;
  }
}
.columns-tree {
  .is-leaf {
    padding: 0 !important;
  }
}
.cAll {
  padding-left: 12px;
}
</style>
